#pragma once
#include <iostream>
#include "../mqcomm/mq_msg.pb.h"
#include "../mqcomm/mq_helper.hpp"
namespace ns_kkymq
{
    class Router
    {
    public:
        Router()
        {
        }
        static bool IsLegalRoutingKey(const std::string &routing_key)
        {
            // routing_key: 只需要判断是否包含有非法字符即可
            // 合法字符(a-z,A-Z,0-9,.,_);
            for (auto &ch : routing_key)
            {
                if ((ch >= 'a' && ch <= 'z') ||
                    (ch >= 'A' && ch <= 'Z') ||
                    (ch >= '0' && ch <= '9') ||
                    ch == '_' || ch == '.')
                {
                    continue;
                }
                return false;
            }
            return true;
        }

        static bool IsLegalBindingKey(const std::string &binding_key)
        {
            // 1.判断是否包含有非法字符 合法字符(a-z,A-Z,0-9, . , _ , * , # );
            for (auto &ch : binding_key)
            {
                if ((ch >= 'a' && ch <= 'z') ||
                    (ch >= 'A' && ch <= 'Z') ||
                    (ch >= '0' && ch <= '9') ||
                    ch == '_' || ch == '.' ||
                    ch == '*' || ch == '#')
                {
                    continue;
                }
                return false;
            }
            // 2. *和#必须独立存在: new.music.*.#
            std::vector<std::string> sub_words;
            StrHelper::split(binding_key, ".", sub_words);
            for (auto &word : sub_words)
            {
                //*或者# 与单词连在一起了  不行
                if (word.size() > 1 && ((word.find("*") != std::string::npos) ||
                    (word.find("#") != std::string::npos)))
                {
                    return false;
                }
            }

            // 3. *和#不能连续出现
            for (int i = 1; i < sub_words.size(); i++)
            {
                if ((sub_words[i] == "#" && sub_words[i - 1] == "*") ||
                    (sub_words[i] == "*" && sub_words[i - 1] == "#") ||
                    (sub_words[i] == "#" && sub_words[i - 1] == "#"))
                {
                    return false;
                }
            }
            return true;
        }

        static bool  route(ExchangeType type, const std::string &routing_key, const std::string &binding_key)
        {
            if (type == ExchangeType::DIRECT)
            {
                return (routing_key == binding_key);
            }
            else if (type == ExchangeType::FANOUT)
            {
                return true;
            }
            else if (type == ExchangeType::TOPIC)
            {
                // 主题交换：要进行模式匹配 news.#   &   news.music.pop
                // 1.将binding_key与routing_key进行字符串分割，得到各个单词的数组
                std::vector<std::string> bkeys, rkeys;
                int n_bkey = StrHelper::split(binding_key, ".", bkeys);
                int n_rkey = StrHelper::split(routing_key, ".", rkeys);
                // 2.定义标记数组，初始化[0][0]位置为true，其他位置为false
                std::vector<std::vector<bool>> dp(n_bkey + 1, std::vector<bool>(n_rkey + 1, false));
                dp[0][0] = true;
                // 3.如果binding_key以#开始，则将#对应行的第0列置为1
                for (int i = 1; i <= n_bkey; i++)
                {
                    if (bkeys[i - 1] == "#")
                    {
                        dp[i][0] = true;
                        continue;
                    }
                    break;
                }
                // 4.使用routing_key中的每一个单词与binding_key中的每一个单词进行匹配并标记数组
                for (int i = 1; i <= n_bkey; i++)
                {
                    for (int j = 1; j <= n_rkey; j++)
                    {
                        // 如果当前bkey是*，或者两个单词相同，表示单词匹配成功，从左上方继承结果
                        if (bkeys[i - 1] == rkeys[j - 1] || bkeys[i - 1] == "*")
                        {
                            dp[i][j] = dp[i - 1][j - 1];
                        }
                        else if (bkeys[i - 1] == "#")
                        {
                            // 如果当前bkey是个#，则需要从左上，左，上，继承结果
                            dp[i][j] = dp[i - 1][j - 1] | dp[i][j - 1] | dp[i - 1][j];
                        }
                    }
                }
                return dp[n_bkey][n_rkey];
            }
            lg(Error, "匹配符号Unknow,无法匹配");
            return false;
        }
    };
}